package cn.change.basic.service.impl;

import cn.change.basic.contants.BaseConstants;
import cn.change.basic.dto.LoginDto;
import cn.change.basic.exception.BusinssException;
import cn.change.basic.service.ILoginService;
import cn.change.basic.util.AjaxResult;
import cn.change.basic.util.HttpClientUtils;
import cn.change.basic.util.MD5Utils;
import cn.change.basic.util.StrUtils;
import cn.change.user.domain.Logininfo;
import cn.change.user.domain.User;
import cn.change.user.domain.Wxuser;
import cn.change.user.mapper.LogininfoMapper;
import cn.change.user.mapper.UserMapper;
import cn.change.user.mapper.WxuserMapper;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements ILoginService {
    @Autowired
    private LogininfoMapper logininfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private WxuserMapper wxuserMapper;
    @Autowired
    private UserMapper userMapper;


    @Override
    public Map<String, Object> account(LoginDto dto) {
        //1.校验参数
        if(StringUtils.isEmpty(dto.getUsername())
            || StringUtils.isEmpty(dto.getPassword())
            || StringUtils.isEmpty(dto.getType())){
            throw new BusinssException("请输入参数！");
        }
        //2.根据username + type 查询logininfo表 同时匹配username phone email
        Logininfo logininfo = logininfoMapper.loadByAcount(dto.getUsername(),dto.getType());
        //3.查询没值  报错
        if(logininfo == null){
            throw new BusinssException("用户不存在00！！");
        }
        //4.查询有值  判断密码（比对密码） 密码不一致报错
        String salt = logininfo.getSalt();
        String md5pwd = MD5Utils.encrypByMd5(dto.getPassword() + salt);
        if(!md5pwd.equals(logininfo.getPassword())){
            throw new BusinssException("用户或密码错误！！！！");
        }
        //5.当登录信息保存到redis 设置过期时间30分钟
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(
                token,
                logininfo,//对象存储到内存
                30,
                TimeUnit.MINUTES
        );
        //6.返回token  + logininfo给前端
        Map<String, Object> map = new HashMap<>();
        map.put("token",token);
        //我们是高级技师 我们需要考虑到将一些敏感信息不要返回给前端  salt password
        logininfo.setSalt(null);
        logininfo.setPassword(null);
        map.put("logininfo",logininfo);
        return map;
    }

    @Override
    public AjaxResult loginWechat(Map<String, String> param) {
        String code = param.get("code");
        /*2.校验参数*/
        if (StringUtils.isEmpty(code)){
            throw  new BusinssException("皇上的圣旨不能为空！！");
        }
        /*根据code,获取从微信得到的参数token*/
        String tokenUrl = BaseConstants.WxConstants.TOKEN_URL
                .replace("APPID",BaseConstants.WxConstants.APPID)
                .replace("SECRET",BaseConstants.WxConstants.SECRET)
                .replace("CODE",code);
        /*4.向微信发起获取token的请求，接收微信响应：access_token + openid*/
        String tokenJsonStr = HttpClientUtils.httpGet(tokenUrl);
        JSONObject tokenObj = JSONObject.parseObject(tokenJsonStr);
        String accessToken = tokenObj.getString("access_token");
        String openId = tokenObj.getString("openid");
      /*  5.根据openid查询本地的t_wxuser表，判断是否已经存在用户*/
        Wxuser wxuser = wxuserMapper.loadByOpenId(openId);
        if (wxuser != null &&  wxuser.getUserId() != null){
             /*存在，并且已经绑定用户，直接免密登录*/
            Logininfo logininfo = logininfoMapper.loadByUserId(wxuser.getUserId());
            //.当登录信息保存到redis 设置过期时间30分钟
            String token = UUID.randomUUID().toString();
            redisTemplate.opsForValue().set(
                    token,
                    logininfo,//对象存储到内存
                    30,
                    TimeUnit.MINUTES
            );
            //6.返回token  + logininfo给前端
            Map<String, Object> map = new HashMap<>();
            map.put("token",token);
            //我们是高级技师 我们需要考虑到将一些敏感信息不要返回给前端  salt password
            logininfo.setSalt(null);
            logininfo.setPassword(null);
            map.put("logininfo",logininfo);
            return AjaxResult.me().setResultObj(map);
        }
        /*。不存在，让页面定位到微信绑定页面
        注意：需要携带access_token + openid回去*/
        String binderParmaStr = "?accessToken="+accessToken+"&openId="+openId;
        return AjaxResult.me().setSuccess(false).setResultObj(binderParmaStr);
    }

    @Override
    public Map<String, Object> binder(Map<String, String> param) {
        String phone = param.get("phone");
        String verifyCode = param.get("verifyCode");
        String accessToken = param.get("accessToken");
        String openId = param.get("openId");
        /*    2.校验参数*/
        if(StringUtils.isEmpty(phone)
                || StringUtils.isEmpty(verifyCode)
                || StringUtils.isEmpty(accessToken)
                || StringUtils.isEmpty(openId)
        ){
            throw new BusinssException("参数为空！！！");
        }
        //3.校验短信验证码
        String smsCodeKey = BaseConstants.VerifyCodeConstants.BUSINESS_BINDER_PREFIX+phone;
        Object smsCodeValueTmp = redisTemplate.opsForValue().get(smsCodeKey);
        if(smsCodeValueTmp == null){
            throw new BusinssException("验证码已过期，请重新获取！！！");
        }
        String smsCodeValue = smsCodeValueTmp.toString().split(":")[0];
        if(!smsCodeValue.equalsIgnoreCase(verifyCode)){
            throw new BusinssException("验证码错误！！");
        }
       /* 3.判断用户是否已经存在*/
        User user = userMapper.loadByPhone(phone);
        Logininfo logininfo =null;
        if (user == null){
           /* 不存在，*/
            user = initUser(phone);
            logininfo = user2logininfo(user);
            logininfoMapper.save(logininfo);//返回自增id
            user.setLogininfoId(logininfo.getId());
            userMapper.save(user);
        }else {
            /*存在*/
            logininfo = logininfoMapper.loadByUserId(user.getId());
        }
        /*4.拼接获取微信微信用户信息的请求，调用微信去获取微信用户基本信息 */
        String wxUserUrl = BaseConstants.WxConstants.WXUSER_URL
                .replace("ACCESS_TOKEN",accessToken)
                .replace("OPENID",openId);
        String wxUserJsonStr = HttpClientUtils.httpGet(wxUserUrl);
        /*5.微信响应结果*/
        Wxuser wxuser = JSONObject.parseObject(wxUserJsonStr, Wxuser.class);
        wxuser.setUserId(user.getId());
        /*绑定*/
        wxuserMapper.save(wxuser);
        /*6.免密登录*/
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(
                token,
                logininfo,//对象存储到内存
                30,
                TimeUnit.MINUTES
        );
        /*6.返回token  + logininfo给前端*/
        Map<String, Object> map = new HashMap<>();
        map.put("token",token);
        //我们是高级技师 我们需要考虑到将一些敏感信息不要返回给前端  salt password
        logininfo.setSalt(null);
        logininfo.setPassword(null);
        map.put("logininfo",logininfo);
        return map;
    }

    private Logininfo user2logininfo(User user) {
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user,logininfo);
        logininfo.setType(1);
        return logininfo;
    }

    private User initUser(String phone) {
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        String salt = StrUtils.getComplexRandomString(32);
        String md5Pwd = MD5Utils.encrypByMd5('1' + salt);
       user.setSalt(salt);
       user.setPassword(md5Pwd);
       return user;
    }
}
